package com.umbacos.udm.client.arch;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Widget;

public class Animator {

	static final public boolean FINISHED=false;
	static final public boolean NOT_FINISHED=true;

	private static final int FRAME_RATE = 33;
	private LinkedHashMap<Widget, Animation> animations = new LinkedHashMap<Widget, Animation>();
	private ArrayList<Animation> addedAnimations = new ArrayList<Animation>();
	private AnimationTimer timer = new AnimationTimer();
	private boolean executingAnimations = FINISHED;

	public void addAnimation(Animation animation) {
		boolean timerIsRunning = !animations.isEmpty();
		if (animation.beforeFirstFrame()==NOT_FINISHED) {
			if (executingAnimations==NOT_FINISHED) {
				addedAnimations.add(animation);
			} else {
				animations.put(animation.getWidget(), animation);
				if (!timerIsRunning) {
					timer.schedule(FRAME_RATE);
				}
			}
		}
	}

	private void executeAnimations() {
		try {
			executingAnimations = NOT_FINISHED;
			for (Iterator<Map.Entry<Widget, Animation>> entries = animations.entrySet().iterator(); entries.hasNext();) {
				Animation animation = entries.next().getValue();
				if (animation.animateOneFrame()==FINISHED) {
					animation.afterLastFrame();
					entries.remove();
				}
			}
		} finally {
			executingAnimations = FINISHED;
		}
	}

	private class AnimationTimer extends Timer {

		public void run() {
			executeAnimations();
			int numberOfWaitingAnimations = addedAnimations.size();
			if (numberOfWaitingAnimations > 0) {
				for (int index = 0; index < numberOfWaitingAnimations; index++) {
					Animation animation = addedAnimations.get(index);
					animations.put(animation.getWidget(), animation);
				}
				addedAnimations.clear();
			}
			if (animations.size() > 0) {
				schedule(FRAME_RATE);
			}
		}
	}
}
